<template>
    <div>
        <mark>我是pages页面的test1.vue页面使用布局页面text.vue进行布局</mark>
        <p>在pages文件夹下新建一个文件会自动生成路由页面的</p>
        <img :src="imgCaptcha" @click="rester"/>
        <div  class="drap" ref="drap">
        <input type="file" @change="handelUpLoad">
        </div>
        <mark>上传文件的进度条111：{{progress+'%'}}</mark>
        <p>--------------------------------</p>
        <button @click="upFile">上传文件</button>
        <mark>计算hash值的进度条：{{hashProgress+'%'}}</mark>
        <!-- 网格进度条布局 -->
        <div class="cube-wrap" :style="{width:widthCp+'px'}">
            <div class="cube" v-for="chunk in chunks" :key="chunk.name">
                <div :class="{
                    'uploading':chunk.progress>0&&chunk.progress<100,
                    'success':chunk.progress==100,
                    'error':chunk.progress<0
                }" :style="{height:chunk.progress+'%'}">
                <i class="el-icon-loading" style="color:#ccc" v-if="chunk.progress>0&&chunk.progress<100"></i>

                </div>
            </div>
        </div>
    </div>
</template>
<script>
import axios from 'axios';
import sparkMd5 from 'spark-md5'
const FILE_SIZE = 0.1*1024*1024;//todo 超过0.5M的文件进行切片
export default {
  layout: 'text',
  data(){
      return{
          imgCaptcha:'',
          file:null,
          progress:0,//这是上传文件的进度条
          hashProgress:0,//计算hash的进度条
          chunks:[],//存储切片的数据
          hash:'',//存储hash值
      }
  },
  mounted(){
      this.rester();
      this.eventDrap();
  },
  computed:{
      widthCp(){
          return Math.ceil(Math.sqrt(this.chunks.length))*16;
      },
      upLoadProgress(){
          if(!this.file||this.chunks.length){
              return 0;
          }
          const load = this.chunks.map(item=>item.chunk.size*item.progress)
                                    .reduce((cur,per)=>cur+per,0)
         return Number((load*100)/this.file.size).toFixed(2);
      }
  },
  methods:{
      eventDrap(){
          const drap = this.$refs.drap;
        //   todo 监听拖拽进入事件
          drap.addEventListener('dragover',e=>{
              drap.style.borderColor = 'red';
              e.preventDefault();
          })
        //   监听拖拽离开事件
          drap.addEventListener('dragleave',e=>{
              drap.style.borderColor = '#ccc';
              e.preventDefault();
          })
          // todo 拖拽到框中的文件进行读取
          drap.addEventListener('drop',e=>{
              const file = e.dataTransfer.files[0];
              drap.style.borderColor = '#ccc';
              e.preventDefault();
              this.file = file;
              console.log(this.file);
          })
      },
    //   读取文件的头信息并进行格式的转化，转为unicloud码，在转16进制
        isReadImg(blob){
            return new Promise((resolve)=>{
                const reader = new FileReader();
                 reader.onload = function () {
                 const ret =  reader.result.split('')
                    .map(v=>v.charCodeAt())
                    .map(v=>v.toString(16).toUpperCase())
                    .join(' ')
                    resolve(ret);
                }
                reader.readAsBinaryString(blob);
            })
        },
        // 判断图片是不是GIF的
        async isGif(file){
            // 图片的类型通过头信息进行判断47 49 46 38 39(37) 61 
            const res = await this.isReadImg(file.slice(0,6));
            console.log(res);
            const isGifImg = res=='47 49 46 38 39 61'|| res=='47 49 46 38 37 61';
            return isGifImg
        },
        // 判断图片是不是png的
        async isPng(file){
            // 图片的类型通过头信息进行判断前8位后面是图片的宽高信息
            // 89 50 4E 47 0D 0A 1A 0A 不知道怎么回事，读取出的文件头信息没有0，有的话不通过
            const res = await this.isReadImg(file.slice(0,8));
            console.log(res);
            const isPngImg = res=='89 50 4E 47 D A 1A A';
            return isPngImg
        },
        // 判断图片是不是jpg的
        async isJpg(file){
            // 图片的类型通过头信息进行判断头两位和尾部后两位
            const len = file.size;
            const start = await this.isReadImg(file.slice(0,2));
            const end = await this.isReadImg(file.slice(-2,len));
            console.log(start,end);
            const isJpgImg =(start=='FF D8')&&(end==='FF D9');
            return isJpgImg
        },
      async isImg(file){
          return await this.isGif(file) || await this.isPng(file) || await this.isJpg(file);
      },
      //TODO 进行文件的切片 FILE_SIZE全局变量
      createChunks(file,size=FILE_SIZE){
          let chunks = [];
          let cut = 0;
          while(cut<file.size){
              chunks.push({index:cut,file:file.slice(cut,cut+size)});
              cut+=size
          }
          return chunks;
      },
      //todo 使用多线程计算hash的值
      hashWork(chunk){
          return new Promise((resolve)=>{
              let work = new Worker('/hash.js');//直接读取静态文件夹下的文件
              work.postMessage({chunks:chunk});//传递给worker数据
              work.onmessage=e=>{//回传给我们的数据
                  console.log('多线程-------',e);
                  const { progress,hash } = e.data;
                  this.hashProgress = Number(progress.toFixed(2))
                  if(hash){
                      resolve(hash);
                  }
              }
          })
      },
      //react中的处理机制，利用空闲时间进行计算
      hashReact(chunks){
          return new Promise(resolve=>{
              const spark = new sparkMd5.ArrayBuffer();
              let count = 0;
                const appendToSpark = async file=>{
                    return new Promise(resolve=>{
                        const reader = new FileReader();
                        reader.readAsArrayBuffer(file);
                        reader.onload = e=>{
                            spark.append(e.target.result);
                            resolve()
                        }
                    })
                }
              const workLoop = async deadline=>{
                // console.log(deadline);
                  while(count<chunks.length&&deadline.timeRemaining()>1){
                    //   空闲且有任务
                    await appendToSpark(chunks[count].file);
                    count++;
                    if(count<chunks.length){
                        this.hashProgress = Number((100*count)/chunks.length).toFixed(2);
                    }else{
                        this.hashProgress = 100;
                        resolve(spark.end());
                    }

                  }
                  window.requestIdleCallback(workLoop);
              }
               window.requestIdleCallback(workLoop);
          })
      },
      async requestChunks(){
          const request = this.chunks.map((chunk,index)=>{
              const formDate = new FormData();
              formDate.append('name',chunk.name);
              formDate.append('hash',chunk.hash);
              formDate.append('chunk',chunk.chunk);
              return formDate
          }).map((form,index)=>axios.post('/api/upload',form,{
              onUploadProgress:progressEvent=>{
                //   此时的进度条是每一个切片的进度条，整体的话需要我们在进行计算的
                  this.chunks[index].progress = (Number(progressEvent.loaded/progressEvent.total)*100).toFixed(2)
              }
               
          }))
          await Promise.all(request);
          await this.mergRequest();//调用默认的请求
      },
      async mergRequest(){
          axios.post('/api/merg',{
              ext:this.file.name.split('.').pop(),//拿到文件的后缀名
              size:Math.ceil(FILE_SIZE),
              hash:this.hash
          })
      },
      async upFile(){
          const chunk = this.createChunks(this.file);
          const hash = await this.hashWork(chunk);
          this.hash = hash;
          console.log('计算的hash值-------',hash);
        //   const hash1 = await this.hashReact(chunk);
        //   console.log('计算的hash1值-------',hash1);
        //   return;

        this.chunks = chunk.map((chunk,index)=>{
            const name = hash+'-'+index;
            return {
                name,
                hash,
                chunk:chunk.file,
                progress:0
            }
        })
        await this.requestChunks()
        //   if(!await this.isImg(this.file)){
        //       console.log('验证错误');
        //       return 
        //   }else{
        //       console.log('验证通过')
        //   }
        // const formDate = new FormData();
        //  console.log(this.file);

        //  formDate.append('name','file');
        //  formDate.append('file',this.file);
        //  console.log(formDate.get('file'));
        //  const res = await axios.post('/api/upload',formDate,{
        //      onUploadProgress: progressEvent=>{//这个是自带的进度条事件
        //          console.log(progressEvent);
        //          this.progress = (Number(progressEvent.loaded/progressEvent.total)*100).toFixed(2)
        //      }
        //  });
         
        //  console.log(res);
      },

      handelUpLoad(e){//上传文件，获取文件的内容
          console.log(e);
          const [file] = e.target.files;
          if(!file) return;
          this.file = file;
      },
      rester(){
          this.imgCaptcha = "/api/svg-img?_t="+new Date().getTime();
      }
  }
}
</script>
<style>
.drap{
    width:100%;
    height:200px;
    text-align:center;
    line-height:200px;
    border:4px dashed #ccc;
}

    .cube{
        width: 14px;
        height: 14px;
        line-height: 12px;
        border: 1px solid black;
        float: left;
        margin: 2px;
        background: #ccc;
        
      
        
    }
    .error{
            background: red;
        }
     .uploading{
            background: orange;
        }
    .success{
            background: green;
        }
</style>